package cn.yangsen.simplebeanmanager.engine;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

import org.apache.commons.collections4.CollectionUtils;

import cn.yangsen.simplebeanmanager.annotation.Detail;
import cn.yangsen.simplebeanmanager.annotation.Rely;
import cn.yangsen.simplebeanmanager.annotation.isActualize;
import cn.yangsen.simplebeanmanager.annotation.作为一个超链接;
import cn.yangsen.simplebeanmanager.annotation.循环的;
import cn.yangsen.simplebeanmanager.annotation.级联;
import cn.yangsen.simplebeanmanager.annotation.限定范围;
import cn.yangsen.simplebeanmanager.bean.html.A;
import cn.yangsen.simplebeanmanager.bean.html.Element;
import cn.yangsen.simplebeanmanager.bean.html.Label;
import cn.yangsen.simplebeanmanager.tool.GenericsTool;
import cn.yangsen.simplebeanmanager.tool.ReflectTool;

public abstract class 生成器
{
	/**
	 * 已经出现在该集合中的类(key)处理次数(value)超过了设置的处理次数，不再处理
	 */
	protected Map<Class<?>, Integer> 已处理类记录;

	protected Element[][] 处理属性集合(final Field[] 属性集合, Object 对象)
	{
		ArrayList<Element[]> 值 = new ArrayList<>();

		Set<Field> 已被级联处理的属性 = null;

		for (Field 属性 : 属性集合)
		{
			if (已被级联处理的属性 != null && 已被级联处理的属性.contains(属性))
			{
				continue;
			}

			// 级联处理的属性
			if (属性.isAnnotationPresent(级联.class))
			{
				if (已被级联处理的属性 == null)
				{
					已被级联处理的属性 = new HashSet<>();
				}
				CollectionUtils.addAll(值, 处理级联属性(属性, 对象, 已被级联处理的属性));
			}
			else
			{
				Element[] es = 处理单个属性(属性, 对象);
				if (es != null)
				{
					值.add(es);
				}
			}
		}
		return 值.stream().toArray(Element[][]::new);
	}

	protected Element[] 处理单个属性(Field 属性, Object 对象)
	{
		if (Modifier.isStatic(属性.getModifiers()))
		{
			return null;
		}

		属性.setAccessible(true);

		// TODO 多个注解都存在的情况下，有问题，根本原因是注解关系没有理清
		if (属性.isAnnotationPresent(isActualize.class))
		{
			return null;
		}
		else if (属性.isAnnotationPresent(Id.class))
		{
			return 处理Id注解的属性值(对象, 属性);
		}
		else if (属性.isAnnotationPresent(限定范围.class))
		{
			return 处理限定范围的属性值(对象, 属性);
		}
		else if (属性.isAnnotationPresent(作为一个超链接.class))
		{
			return 处理AsA注解的属性值(对象, 属性);
		}
		else if (属性.isAnnotationPresent(Rely.class))
		{
			return 处理Rely注解的属性值(对象, 属性);
		}
		else
		{
			Object 值 = ReflectTool.获取对象的属性值(对象, 属性);
			return 处理对象类型(值, 属性, 属性.getType());
		}
	}

	/**
	 * @param 对象
	 * @param 属性
	 * @param 属性的真实类型
	 *            属性的真实类型，为空则取通过Field.getType获取
	 * @return
	 */
	protected Element[] 处理对象类型(Object 值, Field 属性, Class<?> 属性的真实类型)
	{
		if (属性的真实类型 == String.class)
		{
			return 处理String属性值(属性, 值);
		}
		// TODO 对于int、long的类型判断可以优化
		else if (属性的真实类型 == int.class)
		{
			if (值 == null)
			{
				return 处理Int属性值(属性, null);
			}
			else
			{
				return 处理Int属性值(属性, Integer.valueOf((int) 值));
			}
		}
		else if (属性的真实类型 == Integer.class)
		{
			return 处理Int属性值(属性, (Integer) 值);
		}
		else if (属性的真实类型 == short.class)
		{
			if (值 == null)
			{
				return 处理Int属性值(属性, null);
			}
			else
			{
				return 处理Int属性值(属性, Integer.valueOf((short) 值));
			}
		}
		else if (属性的真实类型 == Short.class)
		{
			return 处理Int属性值(属性, (Integer) 值);
		}
		else if (属性的真实类型 == long.class)
		{
			if (值 == null)
			{
				return 处理Long属性值(属性, null);
			}
			else
			{
				return 处理Long属性值(属性, Long.valueOf((long) 值));
			}
		}
		else if (属性的真实类型 == Long.class)
		{
			return 处理Long属性值(属性, (Long) 值);
		}
		else if (属性的真实类型 == float.class)
		{
			if (值 == null)
			{
				return 处理Float属性值(属性, null);
			}
			else
			{
				return 处理Float属性值(属性, Float.valueOf((float) 值));
			}
		}
		else if (属性的真实类型 == Float.class)
		{
			return 处理Float属性值(属性, (Float) 值);
		}
		// TODO 要改为time包
		else if (属性的真实类型 == Date.class)
		{
			return 处理日期属性值(属性, (Date) 值);
		}
		else if (属性的真实类型 == boolean.class)
		{
			if (值 == null)
			{
				return 处理Boolean属性值(属性, Boolean.FALSE);
			}
			return 处理Boolean属性值(属性, Boolean.valueOf((boolean) 值));
		}
		else if (属性的真实类型 == Boolean.class)
		{
			return 处理Boolean属性值(属性, (Boolean) 值);
		}
		else if (属性的真实类型.isArray())
		{
			Class<?> 实际类型 = 属性的真实类型.getComponentType();
			if (实际类型.isPrimitive())
			{
				实际类型 = ReflectTool.获取封装类(实际类型);
			}
			if (值 == null)
			{
				return 处理Iterable属性值(属性, null, 实际类型);
			}
			else
			{
				int len = Array.getLength(值);
				List<Object> list = new ArrayList<>(len);
				for (int i = 0; i < len; i++)
				{
					list.add(Array.get(值, i));
				}
				return 处理Iterable属性值(属性, list, 实际类型);
			}
		}
		else if (属性的真实类型.isEnum())
		{
			return 处理Enum属性值(属性, 值);
		}
		else if (Iterable.class.isAssignableFrom(属性的真实类型))
		{
			Class<?> 实际类型 = GenericsTool.getFieldGenericType(属性);

			if (属性.isAnnotationPresent(OneToMany.class))
			{
				if (!可执行的(实际类型))
				{
					return null;
				}
				锁定一次(实际类型);
				Element[] 结果 = 处理Iterable属性值(属性, (Iterable<?>) 值, 实际类型);
				释放一次(实际类型);
				return 结果;
			}
			else
			{
				return 处理Iterable属性值(属性, (Iterable<?>) 值, 实际类型);
			}
		}
		else if (Modifier.isAbstract(属性的真实类型.getModifiers()))
		{
			return 处理Abstract属性值(属性, 值);
		}
		else
		{
			if (属性.isAnnotationPresent(ManyToOne.class) || 属性.isAnnotationPresent(OneToOne.class))
			{
				if (!可执行的(属性的真实类型))
				{
					return null;
				}
				锁定一次(属性的真实类型);
				Element[] 结果 = 处理Entity注解的属性值(属性, 值);
				释放一次(属性的真实类型);
				return 结果;
			}
			return 处理Entity注解的属性值(属性, 值);
		}
	}

	protected abstract Element[] 处理Boolean属性值(Field 属性, Boolean 值);

	protected abstract Element[] 处理Int属性值(Field 属性, Integer 值);

	protected abstract Element[] 处理Long属性值(Field 属性, Long 值);

	protected abstract Element[] 处理Float属性值(Field 属性, Float 值);

	protected abstract Element[] 处理日期属性值(Field 属性, Date 值);

	protected abstract Element[] 处理String属性值(Field 属性, Object 值);

	protected abstract Element[] 处理Enum属性值(Field 属性, Object 值);

	protected abstract <T> Element[] 处理Iterable属性值(Field 属性, Iterable<? extends T> 值, Class<? extends T> 实际类型);

	protected abstract Element[] 处理Abstract属性值(Field 属性, Object 值);

	protected abstract Element[] 处理Id注解的属性值(Object 对象, Field 属性);

	protected abstract Element[] 处理Entity注解的属性值(Field 属性, Object 值);

	protected abstract Element[] 处理AsA注解的属性值(Object 对象, Field 属性);

	protected abstract Element[] 处理Rely注解的属性值(Object 对象, Field 属性);

	protected abstract Element[] 处理限定范围的属性值(Object 对象, Field 属性);

	protected abstract Element[][] 处理级联属性(Field 属性, Object 对象, Set<Field> 已被级联处理的属性);

	/**
	 * 获取 @Detail 注解配置的描述内容
	 * 
	 * @param 属性
	 * @return
	 */
	protected String 根据注解获取描述(Field 属性)
	{
		if (属性 == null)
		{
			return null;
		}
		Detail 描述 = 属性.getAnnotation(Detail.class);
		if (描述 != null)
		{
			return 描述.value();
		}
		else
		{
			return 属性.getName();
		}
	}

	protected String 获取枚举的描述(Enum<?> 对象)
	{
		Field 属性 = null;
		Class<?> 枚举类 = 对象.getClass();
		try
		{
			属性 = 枚举类.getField(对象.name());
		}
		catch (NoSuchFieldException e)
		{
			e.printStackTrace();
		}
		catch (SecurityException e)
		{
			e.printStackTrace();
		}
		return 根据注解获取描述(属性);
	}

	protected A 根据注解组装超链接(作为一个超链接 超链接注解, Object 对象)
	{
		A 超链接 = new A();
		String[] 方法名数组 = 超链接注解.链接参数();
		String url = 超链接注解.链接地址();
		if (方法名数组 != null)
		{
			for (String 方法名 : 方法名数组)
			{
				Object 需要填充的值 = ReflectTool.执行方法(对象.getClass(), 对象, 方法名);
				if (需要填充的值 != null)
				{
					url = url.replaceFirst("\\{\\}", 需要填充的值.toString());
					continue;
				}
				url = url.replaceFirst("\\{\\}", "");
			}
		}
		超链接.setHref(url);
		Label 超链接描述 = new Label();
		Object 需要填充的属性值 = ReflectTool.执行方法(对象.getClass(), 对象, 超链接注解.显示方法名());
		if (需要填充的属性值 != null)
		{
			超链接描述.setContent(需要填充的属性值.toString());
		}
		超链接.add(超链接描述);
		return 超链接;
	}

	protected String 获取限定范围时传递关键字(限定范围 范围, Object 对象)
	{
		Object obj = ReflectTool.获取对象的属性值(对象, 范围.传递属性());
		if (obj != null)
		{
			return obj.toString();
		}
		return null;
	}

	protected String 获取限定范围时显示内容(限定范围 范围, Object 对象)
	{
		Object obj = ReflectTool.获取对象的属性值(对象, 范围.显示属性());
		if (obj != null)
		{
			return obj.toString();
		}
		return null;
	}

	protected boolean 可执行的(Class<?> 类型)
	{
		if (已处理类记录 == null)
		{
			return true;
		}
		Integer value = 已处理类记录.get(类型);
		if (value == null)
		{
			return true;
		}
		return value > 0;
	}

	protected void 锁定一次(Class<?> 类型)
	{
		循环的 cir = 类型.getAnnotation(循环的.class);
		int 循环次数 = 0;
		if (cir != null)
		{
			循环次数 = cir.value();
		}

		if (已处理类记录 == null)
		{
			已处理类记录 = new HashMap<>();
		}
		else
		{
			Integer value = 已处理类记录.get(类型);

			// 已存在
			if (value != null)
			{
				循环次数 = value - 1;
			}
		}

		已处理类记录.put(类型, 循环次数);
	}

	protected void 释放一次(Class<?> 类型)
	{
		if (已处理类记录 != null)
		{
			Integer value = 已处理类记录.get(类型);
			if (value != null)
			{
				value++;
				已处理类记录.put(类型, value);
			}
		}
	}
}
